{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true,
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Visualizing Networks\n",
    "\n",
    "The following demonstrates basic use of `nupic.frameworks.viz.NetworkVisualizer` to visualize a network.\n",
    "\n",
    "Before you begin, you will need to install the otherwise optional dependencies.  From the root of nupic repository:\n",
    "\n",
    "```\n",
    "pip install --user .[viz]\n",
    "```\n",
    "\n",
    "Setup a simple network so we have something to work with:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from nupic.engine import Network, Dimensions\n",
    "\n",
    "# Create Network instance\n",
    "network = Network()\n",
    "\n",
    "# Add three TestNode regions to network\n",
    "network.addRegion(\"region1\", \"TestNode\", \"\")\n",
    "network.addRegion(\"region2\", \"TestNode\", \"\")\n",
    "network.addRegion(\"region3\", \"TestNode\", \"\")\n",
    "\n",
    "# Set dimensions on first region\n",
    "region1 = network.getRegions().getByName(\"region1\")\n",
    "region1.setDimensions(Dimensions([1, 1]))\n",
    "\n",
    "# Link regions\n",
    "network.link(\"region1\", \"region2\", \"UniformLink\", \"\")\n",
    "network.link(\"region2\", \"region1\", \"UniformLink\", \"\")\n",
    "network.link(\"region1\", \"region3\", \"UniformLink\", \"\")\n",
    "network.link(\"region2\", \"region3\", \"UniformLink\", \"\")\n",
    "\n",
    "# Initialize network\n",
    "network.initialize()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Render with `nupic.frameworks.viz.NetworkVisualizer`, which takes as input any `nupic.engine.Network` instance:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from nupic.frameworks.viz import NetworkVisualizer\n",
    "\n",
    "# Initialize Network Visualizer\n",
    "viz = NetworkVisualizer(network)\n",
    "\n",
    "# Render to dot (stdout)\n",
    "viz.render()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "That's interesting, but not necessarily useful if you don't understand [dot](http://www.graphviz.org/doc/info/lang.html).  Let's capture that output and do something else:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from nupic.frameworks.viz import DotRenderer\n",
    "from io import StringIO\n",
    "\n",
    "outp = StringIO()\n",
    "viz.render(renderer=lambda: DotRenderer(outp))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "`outp` now contains the rendered output, render to an image with `graphviz`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "# Render dot to image\n",
    "from graphviz import Source\n",
    "from IPython.display import Image\n",
    "\n",
    "Image(Source(outp.getvalue()).pipe(\"png\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the example above, each three-columned rectangle is a discrete region, the user-defined name for which is in the middle column.  The left-hand and right-hand columns are respective inputs and outputs, the names for which, e.g. \"bottumUpIn\" and \"bottomUpOut\", are specific to the region type.  The arrows indicate links between outputs from one region to the input of another.\n",
    "\n",
    "I know what you're thinking.  _That's a cool trick, but nobody cares about your contrived example.  I want to see something real!_\n",
    "\n",
    "Continuing below, I'll instantiate a HTMPredictionModel and visualize it.  In this case, I'll use one of the \"hotgym\" examples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from nupic.frameworks.opf.model_factory import ModelFactory\n",
    "\n",
    "# Note: parameters copied from examples/opf/clients/hotgym/simple/model_params.py\n",
    "model = ModelFactory.create({'aggregationInfo': {'hours': 1, 'microseconds': 0, 'seconds': 0, 'fields': [('consumption', 'sum')], 'weeks': 0, 'months': 0, 'minutes': 0, 'days': 0, 'milliseconds': 0, 'years': 0}, 'model': 'HTMPrediction', 'version': 1, 'predictAheadTime': None, 'modelParams': {'sensorParams': {'verbosity': 0, 'encoders': {'timestamp_timeOfDay': {'type': 'DateEncoder', 'timeOfDay': (21, 1), 'fieldname': u'timestamp', 'name': u'timestamp_timeOfDay'}, u'consumption': {'resolution': 0.88, 'seed': 1, 'fieldname': u'consumption', 'name': u'consumption', 'type': 'RandomDistributedScalarEncoder'}, 'timestamp_weekend': {'type': 'DateEncoder', 'fieldname': u'timestamp', 'name': u'timestamp_weekend', 'weekend': 21}}, 'sensorAutoReset': None}, 'spParams': {'columnCount': 2048, 'spVerbosity': 0, 'spatialImp': 'cpp', 'synPermConnected': 0.1, 'seed': 1956, 'numActiveColumnsPerInhArea': 40, 'globalInhibition': 1, 'inputWidth': 0, 'synPermInactiveDec': 0.005, 'synPermActiveInc': 0.04, 'potentialPct': 0.85, 'boostStrength': 3.0}, 'spEnable': True, 'clParams': {'implementation': 'cpp', 'alpha': 0.1, 'verbosity': 0, 'steps': '1,5', 'regionName': 'SDRClassifierRegion'}, 'inferenceType': 'TemporalMultiStep', 'tmEnable': True, 'tmParams': {'columnCount': 2048, 'activationThreshold': 16, 'pamLength': 1, 'cellsPerColumn': 32, 'permanenceInc': 0.1, 'minThreshold': 12, 'verbosity': 0, 'maxSynapsesPerSegment': 32, 'outputType': 'normal', 'initialPerm': 0.21, 'globalDecay': 0.0, 'maxAge': 0, 'permanenceDec': 0.1, 'seed': 1960, 'newSynapseCount': 20, 'maxSegmentsPerCell': 128, 'temporalImp': 'cpp', 'inputWidth': 2048}, 'trainSPNetOnlyIfRequested': False}})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Same deal as before, create a `NetworkVisualizer` instance, render to a buffer, then to an image, and finally display it inline."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# New network, new NetworkVisualizer instance\n",
    "viz = NetworkVisualizer(model._netInfo.net)\n",
    "\n",
    "# Render to Dot output to buffer\n",
    "outp = StringIO()\n",
    "viz.render(renderer=lambda: DotRenderer(outp))\n",
    "\n",
    "# Render Dot to image, display inline\n",
    "Image(Source(outp.getvalue()).pipe(\"png\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In these examples, I'm using `graphviz` to render an image from the `dot` document in Python, but you may want to do something else. `dot` is a generic and flexible graph description language and there are many tools for working with `dot` files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    ""
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2.0
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
